using System;
using System.ServiceModel;
using Framework.Remoting.Conventions;

namespace Framework.Remoting.Client
{
    public abstract class RequestBase : IRequest
    {
        private readonly IChannelFactoryFactory channelFactoryFactory;

        protected RequestBase(IChannelFactoryFactory channelFactoryFactory)
        {
            this.channelFactoryFactory = channelFactoryFactory;
        }

        public abstract T BeginRequest<T>(WcfServiceInfo wcfServiceInfo);

        public abstract void EndRequest<T>(T channel);

        public abstract void Dispose();

        public object Invoke<T>(Func<T, object> fun, WcfServiceInfo wcfServiceInfo)
        {
            var channel = BeginRequest<T>(wcfServiceInfo);
            try
            {
                return fun(channel);
            }
            finally
            {
                EndRequest(channel);
            }
        }

        protected T CreateChannel<T>(WcfServiceInfo wcfServiceInfo)
        {
            return channelFactoryFactory.Create<T>(wcfServiceInfo).CreateChannel(new EndpointAddress(wcfServiceInfo.Uri));
        }

        protected static void ManageChannel<T>(T channel, bool canClose)
        {
            var communicationObject = (ICommunicationObject) channel;

            if (communicationObject.State == CommunicationState.Closed)
            {
                return;
            }
            if (communicationObject.State == CommunicationState.Faulted)
            {
                communicationObject.Abort();
            }
            else if (canClose)
            {
                communicationObject.Close();
            }
        }
    }
}